let [a, b, c] = [1, 2, 3];
console.log(a)
console.log(b)
console.log(c)

let [foo, [[bar, baz]]] = [1,[[2, 3]]];
console.log(foo, bar, baz);

let [ , , third] = ["foo", "bar", "baz"];
console.log(third);

let [head, ...tail] = [1, 2, 3 , 4];
console.log(head)
console.log(tail);

let [x, y, ...z] = ['a']
console.log(x)
console.log(y)
console.log(z)

let [baa] = []
let [bbb, bba] = [1]
// 上面都是可以结构成功
// 因为值为undefined

// 不完全结构
// let [x, y] = [1,2,3];
// let [a, [b], d] = [1,[ 2, 3], 4];

/** 
 * // 报错
let [foo] = 1;
let [foo] = false;
let [foo] = NaN;
let [foo] = undefined;
let [foo] = null;
let [foo] = {};
 * */ 
// 上面的语句都会报错，因为等号右边的值，要么转为对象以后不具备 Iterator 接口
// （前五个表达式），要么本身就不具备 Iterator 接口（最后一个表达式）。
let [xx, yy, zz] = new Set(['a', 'b', 'c']);
console.log(xx);
console.log(yy);
console.log(zz);

// 事实上，只要某种数据结构具有 Iterator 接口，都可以采用数组形式的解构赋值。
function* fibs() {
    let a = 0;
    let b = 1;
    while (true) {
      yield a;
      [a, b] = [b, a + b];
    }
  }
  
  let [first, second, third1, fourth, fifth, sixth] = fibs();
  console.log(first, second, third1, fourth, fifth, sixth);

//   默认
// let [foo = true] = [];
// let [x, y = 'b'] = ['a'];
// let [x, y = 'b'] = ['a', undefined]
// 注意，ES6 内部使用严格相等运算符（===），判断一个位置是否有值。
// 所以，只有当一个数组成员严格等于undefined，默认值才会生效
// let [x = 1] = [undefined];
// x // 1

// let [x = 1] = [null];
// x // null
// 上面代码中，
// 如果一个数组成员是null，默认值就不会生效，因为null不严格等于undefined。
// 默认值可以引用解构赋值的其他变量，但该变量必须已经声明。

// let [x = 1, y = x] = [];     // x=1; y=1
// let [x = 1, y = x] = [2];    // x=2; y=2
// let [x = 1, y = x] = [1, 2]; // x=1; y=2
// let [x = y, y = 1] = [];     // ReferenceError: y is not defined


// 对象的解构赋值
let { dd, cc } = { dd: 'dd', cc: 'cc' }
console.log(dd);
console.log(cc);

// 对象的解构与数组有一个重要的不同。数组的元素是按次序排列的，变量的取值由它的位置决定；
// 而对象的属性没有次序，变量必须与属性同名，才能取到正确的值。
// let { bar, foo } = { foo: 'aa', bar: 'bbb' }
// foo=>'aa'
// bar=>'bbb'

// let { baz } = { foo: "aaa", bar: "bbb" };
// baz // undefined

// 如果变量名与属性名不一致，必须写成下面这样。
// let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
// baz // "aaa"

// let obj = { first: 'hello', last: 'world' };
// let { first: f, last: l } = obj;
// f // 'hello'
// l // 'world'
// 这实际上说明，对象的解构赋值是下面形式的简写
// let { foo: foo, bar: bar } = { foo: "aaa", bar: "bbb" };

// 上面代码中，foo是匹配的模式，baz才是变量。
// 真正被赋值的是变量baz，而不是模式foo。

let obj = {
    p: [
      'Hello',
      { y1: 'World' }
    ]
  };
  
  let { p, p: [x1, { y1 }] } = obj;


  const node = {
    loc: {
      start: {
        line: 1,
        column: 5
      }
    }
  };
  
  let { loc, loc: { start }, loc: { start: { line }} } = node;
  console.log(line) // 1
  console.log(loc)  // Object {start: Object}
  console.log(start) // Object {line: 1, column: 5}

  let obj1 = {};
let arr = [];

({ foo: obj1.prop, bar: arr[0] } = { foo: 123, bar: true });

console.log(obj1) // {prop:123}
console.log(arr) // [true]

// 对象的解构也可以指定默认值。
/*
var {x = 3} = {};
x // 3

var {x, y = 5} = {x: 1};
x // 1
y // 5

var {x: y = 3} = {};
y // 3

var {x: y = 3} = {x: 5};
y // 5

var { message: msg = 'Something went wrong' } = {};
msg // "Something went wrong"
*/
// 默认值生效的条件是，对象的属性值严格等于undefined。

/*
var {x = 3} = {x: undefined};
x // 3

var {x = 3} = {x: null};
x // null
*/
// 如果要将一个已经声明的变量用于解构赋值，必须非常小心。
// 错误的写法
// let x;
// {x} = {x: 1};
// SyntaxError: syntax error
/*
上面代码的写法会报错，因为 JavaScript 引擎会将{x}理解成一个代码块，
从而发生语法错误。只有不将大括号写在行首，
避免 JavaScript 将其解释为代码块，才能解决这个问题
*/
// // 正确的写法
// let x;
// ({x} = {x: 1});

let { log, sin, cos } = Math;
console.log(log)
console.log(sin)
console.log(cos)

/*
let arr = [1, 2, 3];
let {0 : first, [arr.length - 1] : last} = arr;
first // 1
last // 3
*/ 

// 字符串的解构赋值
/*
const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"
*/ 

// 类似数组的对象都有一个length属性，因此还可以对这个属性解构赋值。
let {length : len} = 'hello';
console.log(len) // 5

// 数值和布尔值的解构赋值
// 解构赋值时，如果等号右边是数值和布尔值，则会先转为对象。
let {toString: s} = 123;
console.log(s === Number.prototype.toString) // true

// let {toString: s} = true;
// s === Boolean.prototype.toString // true

// 解构赋值的规则是，只要等号右边的值不是对象或数组，就先将其转为对象。
// 由于undefined和null无法转为对象，所以对它们进行解构赋值，都会报错。
// let { prop: x } = undefined; // TypeError
// let { prop: y } = null; // TypeError
